home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / ExportAIFFSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  15.5 KB  |  473 lines  |  [TEXT/KAHL]

  1. /* ExportAIFFSample.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ExportAIFFSample.h"
  31. #include "Memory.h"
  32. #include "SampleConsts.h"
  33. #include "Files.h"
  34. #include "SampleStorageActual.h"
  35. #include "BufferedFileOutput.h"
  36. #include "Alert.h"
  37.  
  38.  
  39. /* prototype for the function that actually does the work. */
  40. static void                    TryToExportAIFF(SampleStorageActualRec* Sample,
  41.                                             BufferedOutputRec* File, long SamplingRate);
  42.  
  43.  
  44. /* this routine saves the data in the provided sample storage object as an AIFF-C */
  45. /* formatted file.  it handles any error reporting to the user.  the object is */
  46. /* NOT disposed, so the caller has to do that. */
  47. void                                ExportAIFFSample(struct SampleStorageActualRec* TheSample,
  48.                                             long SamplingRate)
  49.     {
  50.         FileSpec*                    WhereToPut;
  51.  
  52.         CheckPtrExistence(TheSample);
  53.         WhereToPut = PutFile("Untitled.AIFF");
  54.         if (WhereToPut != NIL)
  55.             {
  56.                 if (CreateFile(WhereToPut,ApplicationCreator,CODE4BYTES('A','I','F','F')))
  57.                     {
  58.                         FileType*                    FileDesc;
  59.  
  60.                         if (OpenFile(WhereToPut,&FileDesc,eReadAndWrite))
  61.                             {
  62.                                 BufferedOutputRec*    File;
  63.  
  64.                                 File = NewBufferedOutput(FileDesc);
  65.                                 if (File != NIL)
  66.                                     {
  67.                                         TryToExportAIFF(TheSample,File,SamplingRate);
  68.                                         EndBufferedOutput(File);
  69.                                     }
  70.                                  else
  71.                                     {
  72.                                         AlertHalt("There is not enough memory available to export the sample.",NIL);
  73.                                     }
  74.                                 CloseFile(FileDesc);
  75.                             }
  76.                          else
  77.                             {
  78.                                 AlertHalt("Unable to open the file for writing.",NIL);
  79.                             }
  80.                     }
  81.                  else
  82.                     {
  83.                         AlertHalt("Unable to create the file.",NIL);
  84.                     }
  85.                 DisposeFileSpec(WhereToPut);
  86.             }
  87.     }
  88.  
  89.  
  90. /* AIFF/AIFF-C File Format: */
  91. /*     "FORM" */
  92. /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  93. /*     4-byte type */
  94. /*        "AIFF" = AIFF format file */
  95. /*        "AIFC" = AIFF-C format file */
  96. /* in any order, these chunks can occur: */
  97. /*   Version Chunk (this only occurs in AIFF-C files) */
  98. /*     "FVER" */
  99. /*     4-byte big endian length, which should always be the value 4 (four) */
  100. /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  101. /*          probably doesn't matter. */
  102. /*   Common Chunk for AIFF files */
  103. /*     "COMM" */
  104. /*     4-byte big endian length. */
  105. /*        always 18 for AIFF files */
  106. /*     2-byte big endian number of channels */
  107. /*     4-byte big endian number of sample frames */
  108. /*     2-byte big endian number of bits per sample */
  109. /*        a value in the domain 1..32 */
  110. /*     10-byte extended precision number of frames per second */
  111. /*   Common Chunk for AIFF-C files */
  112. /*     "COMM" */
  113. /*     4-byte big endian length. */
  114. /*        22 + compression method string length for AIFF-C files */
  115. /*     2-byte big endian number of channels */
  116. /*     4-byte big endian number of sample frames */
  117. /*     2-byte big endian number of bits per sample */
  118. /*        a value in the domain 1..32 */
  119. /*     10-byte extended precision number of frames per second */
  120. /*     4-byte character code ID for the compression method */
  121. /*        "NONE" means there is no compression method used */
  122. /*     some characters in a string identifying the compression method */
  123. /*        this must be padded to an even number of bytes, but the pad is */
  124. /*        NOT included in the length descriptor for the chunk. */
  125. /*        for uncompressed data, the string should be */
  126. /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  127. /*        the total chunk length is thus 38 bytes. */
  128. /*   Sound Data Chunk */
  129. /*     "SSND" */
  130. /*     4-byte big endian number of bytes in sample data array */
  131. /*     4-byte big endian offset to the first byte of sample data in the array */
  132. /*     4-byte big endian number of bytes to which the sound data is aligned. */
  133. /*     any length vector of raw sound data. */
  134. /*        this must be padded to an even number of bytes, but the pad is */
  135. /*        NOT included in the length descriptor for the chunk. */
  136. /*        Samples are stored in an integral number of bytes, the smallest that */
  137. /*        is required for the specified number of bits.  If this is not an even */
  138. /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  139. /*        Multichannel sound is interleaved with the left channel first. */
  140. static void                    TryToExportAIFF(SampleStorageActualRec* Sample,
  141.                                             BufferedOutputRec* File, long SamplingRate)
  142.     {
  143.         long                            NumSampleFrames;
  144.         long                            BytesPerFrame;
  145.         long                            ActualBytesInTheSampleChunk;
  146.         long                            BytesInTheFormChunk;
  147.         long                            NumberOfChannels;
  148.         long                            BitDepthOfSamples;
  149.         unsigned long            Mantissa;
  150.         unsigned long            Exponent;
  151.         char                            StupidExtendedThing[10];
  152.  
  153.         CheckPtrExistence(Sample);
  154.         CheckPtrExistence(File);
  155.  
  156.         NumSampleFrames = GetSampleStorageActualNumFrames(Sample);
  157.  
  158.         BytesPerFrame = 1;
  159.         switch (GetSampleStorageActualNumChannels(Sample))
  160.             {
  161.                 default:
  162.                     EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  163.                         "GetSampleStorageActualNumChannels"));
  164.                     break;
  165.                 case eSampleStereo:
  166.                     NumberOfChannels = 2;
  167.                     break;
  168.                 case eSampleMono:
  169.                     NumberOfChannels = 1;
  170.                     break;
  171.             }
  172.         BytesPerFrame *= NumberOfChannels;
  173.  
  174.         switch (GetSampleStorageActualNumBits(Sample))
  175.             {
  176.                 default:
  177.                     EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  178.                         "GetSampleStorageActualNumBits"));
  179.                     break;
  180.                 case eSample16bit:
  181.                     BitDepthOfSamples = 16;
  182.                     break;
  183.                 case eSample8bit:
  184.                     BitDepthOfSamples = 8;
  185.                     break;
  186.             }
  187.         BytesPerFrame *= (BitDepthOfSamples / 8);
  188.  
  189.         /* extended 22050 = 400D AC44000000000000 */
  190.         /* extended 22051 = 400D AC46000000000000 */
  191.         /* extended 44100 = 400E AC44000000000000 */
  192.         /* extended 44101 = 400E AC45000000000000 */
  193.         Exponent = 0x401e;
  194.         Mantissa = SamplingRate;
  195.         while ((Mantissa & 0x80000000) == 0)
  196.             {
  197.                 Mantissa = Mantissa << 1;
  198.                 Exponent -= 1;
  199.             }
  200.         StupidExtendedThing[0] = (Exponent >> 8) & 0xff;
  201.         StupidExtendedThing[1] = Exponent & 0xff;
  202.         StupidExtendedThing[2] = (Mantissa >> 24) & 0xff;
  203.         StupidExtendedThing[3] = (Mantissa >> 16) & 0xff;
  204.         StupidExtendedThing[4] = (Mantissa >> 8) & 0xff;
  205.         StupidExtendedThing[5] = Mantissa & 0xff;
  206.         StupidExtendedThing[6] = 0;
  207.         StupidExtendedThing[7] = 0;
  208.         StupidExtendedThing[8] = 0;
  209.         StupidExtendedThing[9] = 0;
  210.  
  211.         ActualBytesInTheSampleChunk = BytesPerFrame * NumSampleFrames;
  212.         if ((ActualBytesInTheSampleChunk % 2) != 0)
  213.             {
  214.                 ActualBytesInTheSampleChunk += 1;
  215.             }
  216.  
  217.         BytesInTheFormChunk = (ActualBytesInTheSampleChunk + 8) + (38 + 8) + (12);
  218.  
  219.         /*     "FORM" */
  220.         if (!WriteBufferedOutput(File,4,"FORM"))
  221.             {
  222.              DiskErrorPoint:
  223.                 AlertHalt("Unable to write to the file.",NIL);
  224.                 return;
  225.             }
  226.  
  227.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  228.         if (!WriteBufferedUnsignedLongBigEndian(File,BytesInTheFormChunk))
  229.             {
  230.                 goto DiskErrorPoint;
  231.             }
  232.  
  233.         /*     4-byte type */
  234.         /*        "AIFF" = AIFF format file */
  235.         /*        "AIFC" = AIFF-C format file */
  236.         if (!WriteBufferedOutput(File,4,"AIFC"))
  237.             {
  238.                 goto DiskErrorPoint;
  239.             }
  240.  
  241.         /*   Version Chunk (this only occurs in AIFF-C files) */
  242.  
  243.         /*     "FVER" */
  244.         if (!WriteBufferedOutput(File,4,"FVER"))
  245.             {
  246.                 goto DiskErrorPoint;
  247.             }
  248.  
  249.         /*     4-byte big endian length, which should always be the value 4 (four) */
  250.         if (!WriteBufferedUnsignedLongBigEndian(File,4))
  251.             {
  252.                 goto DiskErrorPoint;
  253.             }
  254.  
  255.         /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  256.         /*          probably doesn't matter. */
  257.         if (!WriteBufferedOutput(File,4,"\xa2\x80\x51\x40"))
  258.             {
  259.                 goto DiskErrorPoint;
  260.             }
  261.  
  262.         /*   Common Chunk for AIFF-C files */
  263.  
  264.         /*     "COMM" */
  265.         if (!WriteBufferedOutput(File,4,"COMM"))
  266.             {
  267.                 goto DiskErrorPoint;
  268.             }
  269.  
  270.         /*     4-byte big endian length. */
  271.         /*        22 + compression method string length for AIFF-C files */
  272.         if (!WriteBufferedUnsignedLongBigEndian(File,38))
  273.             {
  274.                 goto DiskErrorPoint;
  275.             }
  276.  
  277.         /*     2-byte big endian number of channels */
  278.         if (!WriteBufferedUnsignedShortBigEndian(File,NumberOfChannels))
  279.             {
  280.                 goto DiskErrorPoint;
  281.             }
  282.  
  283.         /*     4-byte big endian number of sample frames */
  284.         if (!WriteBufferedUnsignedLongBigEndian(File,NumSampleFrames))
  285.             {
  286.                 goto DiskErrorPoint;
  287.             }
  288.  
  289.         /*     2-byte big endian number of bits per sample */
  290.         /*        a value in the domain 1..32 */
  291.         if (!WriteBufferedUnsignedShortBigEndian(File,BitDepthOfSamples))
  292.             {
  293.                 goto DiskErrorPoint;
  294.             }
  295.  
  296.         /*     10-byte extended precision number of frames per second */
  297.         if (!WriteBufferedOutput(File,10,StupidExtendedThing))
  298.             {
  299.                 goto DiskErrorPoint;
  300.             }
  301.  
  302.         /*     4-byte character code ID for the compression method */
  303.         /*        "NONE" means there is no compression method used */
  304.         if (!WriteBufferedOutput(File,4,"NONE"))
  305.             {
  306.                 goto DiskErrorPoint;
  307.             }
  308.  
  309.         /*     some characters in a string identifying the compression method */
  310.         /*        this must be padded to an even number of bytes, but the pad is */
  311.         /*        NOT included in the length descriptor for the chunk. */
  312.         /*        for uncompressed data, the string should be */
  313.         /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  314.         /*        the total chunk length is thus 38 bytes. */
  315.         if (!WriteBufferedOutput(File,16,"\x0enot compressed\x00"))
  316.             {
  317.                 goto DiskErrorPoint;
  318.             }
  319.  
  320.         /*   Sound Data Chunk */
  321.  
  322.         /*     "SSND" */
  323.         if (!WriteBufferedOutput(File,4,"SSND"))
  324.             {
  325.                 goto DiskErrorPoint;
  326.             }
  327.  
  328.         /*     4-byte big endian number of bytes in sample data array */
  329.         if (!WriteBufferedUnsignedLongBigEndian(File,BytesPerFrame * NumSampleFrames))
  330.             {
  331.                 goto DiskErrorPoint;
  332.             }
  333.  
  334.         /*     4-byte big endian offset to the first byte of sample data in the array */
  335.         if (!WriteBufferedUnsignedLongBigEndian(File,0))
  336.             {
  337.                 goto DiskErrorPoint;
  338.             }
  339.  
  340.         /*     4-byte big endian number of bytes to which the sound data is aligned. */
  341.         if (!WriteBufferedUnsignedLongBigEndian(File,0))
  342.             {
  343.                 goto DiskErrorPoint;
  344.             }
  345.  
  346.         /*     any length vector of raw sound data. */
  347.         /*        this must be padded to an even number of bytes, but the pad is */
  348.         /*        NOT included in the length descriptor for the chunk. */
  349.         /*        Samples are stored in an integral number of bytes, the smallest that */
  350.         /*        is required for the specified number of bits.  If this is not an even */
  351.         /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  352.         /*        Multichannel sound is interleaved with the left channel first. */
  353.         switch (GetSampleStorageActualNumChannels(Sample))
  354.             {
  355.                 default:
  356.                     EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  357.                         "GetSampleStorageActualNumChannels"));
  358.                     break;
  359.                 case eSampleStereo:
  360.                     switch (GetSampleStorageActualNumBits(Sample))
  361.                         {
  362.                             default:
  363.                                 EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  364.                                     "GetSampleStorageActualNumBits"));
  365.                                 break;
  366.                             case eSample16bit:
  367.                                 {
  368.                                     long                        Scan;
  369.  
  370.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  371.                                         {
  372.                                             largefixedsigned        SampleWord;
  373.  
  374.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  375.                                             if (!WriteBufferedSignedShortBigEndian(File,
  376.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  377.                                                 {
  378.                                                     goto DiskErrorPoint;
  379.                                                 }
  380.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  381.                                             if (!WriteBufferedSignedShortBigEndian(File,
  382.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  383.                                                 {
  384.                                                     goto DiskErrorPoint;
  385.                                                 }
  386.                                         }
  387.                                     /* 16-bit is always even aligned */
  388.                                 }
  389.                                 break;
  390.                             case eSample8bit:
  391.                                 {
  392.                                     long                        Scan;
  393.  
  394.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  395.                                         {
  396.                                             largefixedsigned        SampleWord;
  397.  
  398.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  399.                                             if (!WriteBufferedSignedChar(File,
  400.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT)))
  401.                                                 {
  402.                                                     goto DiskErrorPoint;
  403.                                                 }
  404.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  405.                                             if (!WriteBufferedSignedChar(File,
  406.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT)))
  407.                                                 {
  408.                                                     goto DiskErrorPoint;
  409.                                                 }
  410.                                         }
  411.                                     /* stereo is always even aligned */
  412.                                 }
  413.                                 break;
  414.                         }
  415.                     break;
  416.                 case eSampleMono:
  417.                     switch (GetSampleStorageActualNumBits(Sample))
  418.                         {
  419.                             default:
  420.                                 EXECUTE(PRERR(ForceAbort,"TryToExportAIFF:  bad value from "
  421.                                     "GetSampleStorageActualNumBits"));
  422.                                 break;
  423.                             case eSample16bit:
  424.                                 {
  425.                                     long                        Scan;
  426.  
  427.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  428.                                         {
  429.                                             largefixedsigned        SampleWord;
  430.  
  431.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  432.                                             if (!WriteBufferedSignedShortBigEndian(File,
  433.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  434.                                                 {
  435.                                                     goto DiskErrorPoint;
  436.                                                 }
  437.                                         }
  438.                                     /* 16-bit is always even aligned */
  439.                                 }
  440.                                 break;
  441.                             case eSample8bit:
  442.                                 {
  443.                                     long                        Scan;
  444.  
  445.                                     for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  446.                                         {
  447.                                             largefixedsigned        SampleWord;
  448.  
  449.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  450.                                             if (!WriteBufferedSignedChar(File,
  451.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT)))
  452.                                                 {
  453.                                                     goto DiskErrorPoint;
  454.                                                 }
  455.                                         }
  456.                                     /* 8-bit mono might be unaligned */
  457.                                     if ((NumSampleFrames % 2) != 0)
  458.                                         {
  459.                                             /* write an extra pad byte */
  460.                                             if (!WriteBufferedUnsignedChar(File,0))
  461.                                                 {
  462.                                                     goto DiskErrorPoint;
  463.                                                 }
  464.                                         }
  465.                                 }
  466.                                 break;
  467.                         }
  468.                     break;
  469.             }
  470.  
  471.         /* all done */
  472.     }
  473.